package words;

import java.util.*;
import java.io.*;

public class SgmlDocument {
  
  TagDefinition m_tagDef;
  
  // text without annotations
  String m_strText;
  // tight positions vs. normal positions
  int m_vecPos[];
  // annotations list, ordered by position and length
  LinkedList m_lstAnno;

  // private members
  protected int m_nPos;
  protected int m_nTight;
  
  public SgmlDocument(TagDefinition tagDef)
  {
    m_tagDef = tagDef;
    m_strText = new String();
    m_lstAnno = new LinkedList();
    m_nPos = m_nTight = 0;
  }
  

  public boolean load(String strFile)
  {
    String strTText = new String();
    // read file line by line
    try {
      BufferedReader file = new BufferedReader(new FileReader(strFile));

      String strLine = file.readLine();
      while (strLine != null) {
        strTText += strLine + "\n";
        strLine = file.readLine();
      }
    }
    catch (IOException e) {
      System.out.println(e);
      return false;
    }
    
    // read annotations
    boolean bRes = read(strTText);

    // compute tight vs. normal positions
    m_vecPos = new int[m_nTight];
    int j = 0;
    for (int i = 0; i < m_strText.length(); i++)
      if (!Character.isWhitespace(m_strText.charAt(i)))
        m_vecPos[j++] = i;

    // sort annotations list
    Annotation[] annos = new Annotation[m_lstAnno.size()];
    m_lstAnno.toArray(annos);
    Arrays.sort(annos);
    m_lstAnno = new LinkedList();
    for (int i = 0; i < annos.length; i++)
      m_lstAnno.add(annos[i]);

    return bRes;
  }


  public boolean read(String strTText)
  {
    m_nPos = m_nTight = 0;

    while (m_nPos < strTText.length()) {
      char c = strTText.charAt(m_nPos);
      if (c == '<') {
        int nEnd = strTText.indexOf('>', m_nPos);
        if (nEnd == -1) {
          System.err.print("unmatched \'<\' at position ");
          System.err.println(m_nPos);
          return false;
        }
		
        // read annotation
        String strAnnotation = strTText.substring(m_nPos + 1, nEnd);
        // read annotated text
        m_nPos = nEnd + 1;
        if (!read(strTText, strAnnotation))
          return false;
      }
      else {
        m_strText += c;
        if (!Character.isWhitespace(c))
          m_nTight++;
        m_nPos++;
      }
    }
    
    return true;
  }


  public boolean read(String strTText, String strAnno)
  {
    StringTokenizer strTok = new StringTokenizer(strAnno);
    String strTag = strTok.nextToken();
    String strEndTag = "/" + strTag; 
    
    int nBegin = m_nTight;
    while (m_nPos < strTText.length()) {
      char c = strTText.charAt(m_nPos);
      if (c == '<') {
        int nEnd = strTText.indexOf('>', m_nPos);
        if (nEnd == -1) {
          System.err.print("unmatched \'<\' at position ");
          System.err.println(m_nPos);
          return false;
        }
	
        // read annotation
        String strAnnotation = strTText.substring(m_nPos + 1, nEnd);
        if (strAnnotation.equalsIgnoreCase(strEndTag)) {
          // create new Annotation object
          String strPlain = m_strText.substring(nBegin);
          Annotation anno = new Annotation(m_tagDef, strAnno, 
                                           nBegin, m_nTight - nBegin);
          m_lstAnno.add(anno);
          m_nPos = nEnd + 1;
          return true;
        }
        else {
          m_nPos = nEnd + 1;
          if (!read(strTText, strAnnotation))
            return false;
        }
      }
      else {
        m_strText += c;
        if (!Character.isWhitespace(c))
          m_nTight++;
        m_nPos++;
      }
    }

    return true;
  }

  
  public LinkedList getAnnotations()
  {
    return m_lstAnno;
  }

  
  public LinkedList getAnnotations(String strTag)
  {
    LinkedList lstAnno = new LinkedList();
    int nId = m_tagDef.getId(strTag);
    
    ListIterator it = m_lstAnno.listIterator();
    while (it.hasNext()) {
      Annotation anno = (Annotation) it.next();
      if (anno.m_nId == nId)
        lstAnno.add(anno);
    }
    
    return lstAnno;
  }
  
  
  public LinkedList getAnnotations(String strTag, double conf)
  {
    LinkedList lstAnno = new LinkedList();
    int nId = m_tagDef.getId(strTag);
    
    ListIterator it = m_lstAnno.listIterator();
    while (it.hasNext()) {
      Annotation anno = (Annotation) it.next();
      if (anno.m_nId == nId) {
        String strConf = (String) anno.m_mapAtt.get("conf");
        if (strConf == null)
          System.err.println("Found annotation wo confidence!");
        else {
          double dconf = Double.parseDouble(strConf);
          if (dconf >= conf)
            lstAnno.add(anno);
        }
      }
    }
    
    return lstAnno;
  }
  
  
  public String getText()
  {
    return m_strText;
  }

  
  public String getTightText()
  {
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < m_vecPos.length; i++)
      sb.append(m_strText.charAt(m_vecPos[i]));

    return sb.toString();
  }

  public String getText(Annotation anno)
  {
    return m_strText.substring(m_vecPos[anno.m_nBegin], 
                               m_vecPos[anno.m_nBegin + anno.m_nLen - 1] + 1);
  }

  public String getTightText(Annotation anno)
  {
    StringBuffer sb = new StringBuffer();
    for (int i = anno.m_nBegin; i < anno.m_nBegin + anno.m_nLen; i++)
      sb.append(m_strText.charAt(m_vecPos[i]));

    return sb.toString();    
  }

}
